


#ifndef EXPRESSION_H
#define EXPRESSION_H



#include <ostream>
#include "collection.h"



class Category;
class Subject;



class Expression
{
public:
    virtual bool check( Subject *owner ) const =0;
    virtual void putText( std::ostream &S, Subject *owner, bool invert ) const =0;
    
    void invert() { m_bInverted = !m_bInverted; }
    bool isInverted() const { return m_bInverted; }
    
    static uint8_t complexity(){ return 0; }
    
protected:
    Expression();
    bool straight( Subject *owner ) const;

    bool m_bInverted;
};



class ExpressionCategory : public Expression
{
public:
    virtual ~ExpressionCategory();
    
protected:
    ExpressionCategory( Category *cat );
    ExpressionCategory( const ExpressionCategory & );
    Category *m_pCategory;
};



class ExpAllTellTruth : public ExpressionCategory
{
public:
    static Expression *createExpression( Category *cat, Subject *owner );
    virtual bool check( Subject *owner ) const;
    virtual void putText( std::ostream &S, Subject *owner, bool invert ) const;
    
protected:
    ExpAllTellTruth( Category *cat, Subject *owner );
    ExpAllTellTruth( Category *cat );
};



class ExpAllLie : public ExpAllTellTruth
{
public:
    static Expression *createExpression( Category *cat, Subject *owner );
    virtual bool check( Subject *owner ) const;
    virtual void putText( std::ostream &S, Subject *owner, bool invert ) const;
    
protected:
    ExpAllLie( Category *cat, Subject *owner );
};



class ExpTellTruthOrLie : public ExpressionCategory
{
public:
    static Expression *createExpression( Category *cat, Subject *subj );
    virtual bool check( Subject *owner ) const;
    virtual void putText( std::ostream &S, Subject *owner, bool invert ) const;
    
protected:
    ExpTellTruthOrLie( Category *cat, Subject *owner );
};



class ExpNTellTruth : public ExpressionCategory
{
public:
    static Expression *createExpression( Category *cat, Subject *subj );
    virtual bool check( Subject *owner ) const;
    virtual void putText( std::ostream &S, Subject *owner, bool invert ) const;
    
protected:
    ExpNTellTruth( Category *cat );

    uint8_t m_nCount;
};



typedef Collection <Expression> CollectionExpressions;


/// \return - a string which gives a word for the number like: 2 - "two"
const char *ordinal( uint8_t num );


/// \return - makes the first letter of a string capital and outputs to the stream
void capitalize( std::ostream &S, const char *str );



#endif
